﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using DevExpress.XtraTreeList.Nodes;
using DevExpress.XtraTreeList;
using System.IO;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace WebServices.Tuan2
{
    public partial class Form1 : Form
    {
        const string path = @"f:\test\book.xml";
        const string pathToXsd = @"f:\test\book.xsd";
        List<Book> books = new List<Book>();
        List<Book> books1 = new List<Book>();
        List<Category> categories;
        XmlReaderSettings xrs;
        XmlReader xr;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            categories = new List<Category>{
                new Category(){ CategoryId = 0, Name = "0" },
                new Category(){ CategoryId = 1, Name = "1" },
                new Category(){ CategoryId = 2, Name = "2" },
                new Category(){ CategoryId = 3, Name = "3" },
            };

            lupCategories.Properties.DataSource = categories;
            lupCategories.Properties.ValueMember = "CategoryId";
            lupCategories.Properties.DisplayMember = "Name";
            lupCategories.ItemIndex = 0;


            treeList1.ForceInitialize();

            LoadBookXml();

        }

        private void LoadBookXml()
        {
            treeList1.Nodes.Clear();

            #region xmldocument
            //XmlDocument xmldoc = new XmlDocument();
            //xmldoc.Load(path);

            //XmlNodeList xmlbooks = xmldoc.SelectNodes("//books/book");

            //for (int i = 1; i <= xmlbooks.Count; i++)
            //{
            //    Book book = new Book();
            //    string xPathExpression = "/books/book[" + i + "]";

            //    XmlNode xmlnode = xmldoc.SelectSingleNode(xPathExpression + "/title");
            //    book.Title = xmlnode.InnerText;

            //    TreeListNode node = treeList1.AppendNode(null, null);
            //    node.SetValue("name", book.Title);

            //    XmlNodeList authors = xmldoc.SelectNodes(xPathExpression + "/author");

            //    book.AuthorName = new List<string>();

            //    for (int j = 1; j <= authors.Count; j++)
            //    {
            //        xmlnode = xmldoc.SelectSingleNode(xPathExpression + "/author[" + j + "]");
            //        book.AuthorName.Add(xmlnode.InnerText);

            //        TreeListNode childnode = treeList1.AppendNode(null, node);
            //        childnode.SetValue("name", xmlnode.InnerText);
            //    }

            //    xmlnode = xmldoc.SelectSingleNode(xPathExpression + "/price");
            //    book.Price = Convert.ToDecimal(xmlnode.InnerText);

            //    xmlnode = xmldoc.SelectSingleNode(xPathExpression + "/year");
            //    book.Year = Convert.ToInt32(xmlnode.InnerText);

            //    xmlnode = xmldoc.SelectSingleNode(xPathExpression + "/language");
            //    book.Language = xmlnode.InnerText;

            //    this.books.Add(book);
            //}

            #endregion

            #region xmlreader

            xrs = new XmlReaderSettings();
            xrs.IgnoreComments = true;
            xrs.IgnoreWhitespace = true;
            xrs.CloseInput = true;
            xrs.ValidationType = ValidationType.Schema;
            xrs.Schemas.Add("urn:bookstore-schema", pathToXsd); // targetNamespace, pathToXsd
            //xrs.ValidationEventHandler += new ValidationEventHandler(xrs_ValidationEventHandler);

            

            xr = XmlReader.Create(path, xrs);

            TreeListNode node = null;

            if (xr.ReadToDescendant("book"))
            {
                do
                {
                    node = treeList1.AppendNode(null, null);
                    node.SetValue("id", xr["id"]);

                    xr.ReadToDescendant("title");

                    #region book class
                    //var book = new Book();

                    //book.Title = reader.ReadElementContentAsString();
                    //book.Price = reader.ReadElementContentAsDecimal();
                    //book.Year = reader.ReadElementContentAsInt();
                    //book.AuthorName = new List<string>();

                    //while (reader.LocalName == "author")
                    //    book.AuthorName.Add(reader.ReadElementContentAsString());

                    //book.Language = reader.ReadElementContentAsString();
                    #endregion

                    node.SetValue("books", xr.ReadElementContentAsString());

                    xr.ReadToNextSibling("author");

                    TreeListNode childnode;

                    while (xr.LocalName == "author")
                    {
                        childnode = treeList1.AppendNode(null, node);
                        childnode.SetValue("books", xr.ReadElementContentAsString());
                    }

                } while (xr.ReadToFollowing("book"));
            }

            xr.Close();

            //while (xr.Read())
            //{
            //    if (xr.NodeType == XmlNodeType.Element && xr.LocalName == "book")
            //    {
            //        TreeListNode node = treeList1.AppendNode(null, null);
            //        node.SetValue("id", xr["id"]);

            //        xr.ReadToDescendant("title");

            //        #region book class
            //        //var book = new Book();

            //        //book.Title = reader.ReadElementContentAsString();
            //        //book.Price = reader.ReadElementContentAsDecimal();
            //        //book.Year = reader.ReadElementContentAsInt();
            //        //book.AuthorName = new List<string>();

            //        //while (reader.LocalName == "author")
            //        //    book.AuthorName.Add(reader.ReadElementContentAsString());

            //        //book.Language = reader.ReadElementContentAsString();
            //        #endregion

            //        node.SetValue("books", xr.ReadElementContentAsString());

            //        xr.ReadToNextSibling("author");

            //        TreeListNode childnode;

            //        while (xr.LocalName == "author")
            //        {
            //            childnode = treeList1.AppendNode(null, node);
            //            childnode.SetValue("books", xr.ReadElementContentAsString());
            //        }
                    
            //    }
            //}

            //xr.Close();

            #endregion

        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            //add to book list
            AddToBookList1();
        }

        private void AddToBookList1()
        {
            xr = XmlReader.Create(path, xrs);
            int id = 0;

            if (xr.ReadToDescendant("book"))
            {
                do
                {
                    id = Convert.ToInt32(xr["id"]);
                } while (xr.ReadToFollowing("book"));
            }

            xr.Close();

            Book book = new Book
            {
                Status = "create",
                Title = txtTitle.Text,
                AuthorName = memoAuthor.Lines.ToList(),
                //CategoryId = (int)lupCategories.EditValue,
                Language = radioGroup1.SelectedIndex == 0 ? "en" : "vi",
                Price = Convert.ToDecimal(spinPrice.EditValue),
                Year = Convert.ToInt32(spinYear.EditValue)
            };

            if (books1.Count > 0)
            {
                foreach (var b in books1)
                {
                    if (b.Status == "create")
                    {
                        id = id > b.Id ? id : b.Id;
                    }
                }
            }

            book.Id = id > 0 ? (++id) : 1;

            books1.Add(book);

            //add to tree list
            AddToTreeList(id);
        }

        private void AddToTreeList(int id)
        {
            TreeListNode node = treeList1.AppendNode(null, null);

            node.SetValue("id", id); 
            node.SetValue("books", txtTitle.Text);

            TreeListNode childNode = null;

            foreach (var item in memoAuthor.Lines)
            {
                childNode = treeList1.AppendNode(null, node);
                childNode.SetValue("books", item);
            }
        }

        private void btnUpdate_Click(object sender, EventArgs e)
        {
            if (treeList1.Nodes.Count == 0)
            {
                return;
            }

            //add to book list 
            TreeListNode node = GetFocusedNode();

            int id = Convert.ToInt32(node.GetValue("id"));

            int index = books1.FindIndex(b => b.Id == id);

            if (index == -1)
            {
                Book book = new Book();

                book.Id = Convert.ToInt32(node.GetValue("id"));
                book.Status = "modify";
                book.Title = txtTitle.Text;
                book.AuthorName = memoAuthor.Lines.ToList();
                //book.CategoryId = (int)lupCategories.EditValue;
                book.Language = radioGroup1.SelectedIndex == 0 ? "en" : "vi";
                book.Price = Convert.ToDecimal(spinPrice.EditValue);
                book.Year = Convert.ToInt32(spinYear.EditValue);

                books1.Add(book);
            }
            else
            {
                books1[index].Title = txtTitle.Text;
                books1[index].AuthorName = memoAuthor.Lines.ToList();
                //books1[index].CategoryId = (int)lupCategories.EditValue;
                books1[index].Language = radioGroup1.SelectedIndex == 0 ? "en" : "vi";
                books1[index].Price = Convert.ToDecimal(spinPrice.EditValue);
                books1[index].Year = Convert.ToInt32(spinYear.EditValue);
            }
            

            //update tree list 
            UpdateTreeList(node);
        }

        private void UpdateTreeList(TreeListNode node)
        {
            node.SetValue("books", txtTitle.Text);
            node.Nodes.Clear();

            TreeListNode childNode = null;

            foreach (var item in memoAuthor.Lines)
            {
                childNode = treeList1.AppendNode(null, node);
                childNode.SetValue("books", item);
            }
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (treeList1.Nodes.Count == 0)
                return;

            //delete in book list 1

            TreeListNode node = GetFocusedNode();

            int id = Convert.ToInt32(node.GetValue("id"));

            int index = books1.FindIndex(b=>b.Id == id);

            if (index != -1)
            {
                if (books1[index].Status == "create")
                    books1.Remove(books1[index]);
                else
                    books1[index].Status = "delete";
            }
            else
            {
                var book = new Book
                {
                    Status = "delete",
                    Id = id
                };

                books1.Add(book);
            }

            //delete in tree list
            treeList1.DeleteNode(node);
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            #region xmldocument
            
            if (books1.Count > 0)
            {
                xr = XmlReader.Create(path, xrs);

                XmlDocument xdoc = new XmlDocument();
                
                xdoc.Load(xr);

                xr.Close();

                XmlNamespaceManager namespaces = new XmlNamespaceManager(xdoc.NameTable);
                namespaces.AddNamespace("bk", xdoc.DocumentElement.NamespaceURI);

                foreach (var book in books1)
                {
                    if (book.Status == "modify")
                    {
                        //Select the book node with the matching title

                        XmlNode oldBook;

                        oldBook = xdoc.SelectSingleNode("/bk:books/bk:book[@id='" + book.Id + "']", namespaces);

                        XmlElement newBook = xdoc.CreateElement("book", xdoc.DocumentElement.NamespaceURI);

                        //to prevent blank xmlns attributes, add the node to the document 
                        //before specify its content.

                        xdoc.DocumentElement.ReplaceChild(newBook, oldBook);

                        newBook.SetAttribute("id", book.Id.ToString());

                        newBook.InnerXml = "<title>" + book.Title + "</title>"
                                            + "<price>" + book.Price + "</price>"
                                            + "<year>" + book.Year + "</year>";

                        foreach (var author in book.AuthorName)
                            newBook.InnerXml += "<author>" + author + "</author>";

                        newBook.InnerXml += "<language>" + book.Language + "</language>";

                        //save the output to a file
                        xdoc.Save(path);
                    }
                    else if (book.Status == "delete")
                    {
                        //Select the book node with the matching title
                        XmlNode delBook;

                        delBook = xdoc.SelectSingleNode("/bk:books/bk:book[@id='" + book.Id + "']", namespaces);

                        xdoc.DocumentElement.RemoveChild(delBook);

                        //save the output to a file
                        xdoc.Save(path);
                    }
                    else
                    {
                        XmlElement newBook = xdoc.CreateElement("book", xdoc.DocumentElement.NamespaceURI);

                        //to prevent blank xmlns attributes
                        xdoc.DocumentElement.InsertAfter(newBook, xdoc.DocumentElement.LastChild);

                        newBook.SetAttribute("id", book.Id.ToString());

                        newBook.InnerXml = "<title>" + book.Title + "</title>"
                                            + "<price>" + book.Price + "</price>"
                                            + "<year>" + book.Year + "</year>";

                        foreach (var author in book.AuthorName)
                            newBook.InnerXml += "<author>" + author + "</author>";

                        newBook.InnerXml += "<language>" + book.Language + "</language>";

                        //save the output to a file
                        xdoc.Save(path);
                    }
                }

                books1.Clear();
            }
            
            #endregion

            #region xml serialization

            //if (books1.Count > 0)
            //{
            //    XmlSerializer xs = new XmlSerializer(typeof(Books));
            //    FileInfo fi = new FileInfo("test.xml");
            //    Stream inStream = fi.OpenRead();
            //    Books r = xs.Deserialize(inStream) as Books;
            //    inStream.Close();


            //    r.ListBook.Add(new Book());


            //    Stream outStream = fi.OpenWrite();
            //    xs.Serialize(outStream, r);
            //    outStream.Close();
            //}

            #endregion
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            LoadBookXml();
            books1.Clear();
        }

        private void treeList1_Click(object sender, EventArgs e)
        {
            if (treeList1.Nodes.Count == 0) return;

            TreeListNode node = GetFocusedNode();

            string id = node.GetDisplayText("id");

            int index = books1.FindIndex(b => b.Id == Convert.ToInt32(id));

            if (index == -1)
            {
                xr = XmlReader.Create(path, xrs);

                if (xr.ReadToDescendant("book"))
                {
                    do
                    {
                        if (xr["id"] == id)
                        {
                            xr.ReadStartElement("book");
                            txtTitle.Text = xr.ReadElementContentAsString();
                            spinPrice.EditValue = xr.ReadElementContentAsDecimal();
                            spinYear.EditValue = xr.ReadElementContentAsInt();

                            List<string> lsAuthor = new List<string>();

                            while (xr.LocalName == "author")
                                lsAuthor.Add(xr.ReadElementContentAsString());

                            memoAuthor.Lines = lsAuthor.ToArray();

                            radioGroup1.SelectedIndex = xr.ReadElementContentAsString() == "en" ? 0 : 1;

                            break;
                        }
                    } while (xr.ReadToFollowing("book"));
                }

                xr.Close();
            }
            else
            {
                txtTitle.Text = books1[index].Title;
                spinPrice.EditValue = books1[index].Price;
                spinYear.EditValue = books1[index].Year;
                memoAuthor.Lines = books1[index].AuthorName.ToArray();
                radioGroup1.SelectedIndex = books1[index].Language == "en" ? 0 : 1;
            }

        }

        private TreeListNode GetFocusedNode()
        {
            TreeListNode node = treeList1.FocusedNode;

            node = (node.ParentNode == null ? node : node.ParentNode);
            return node;
        }

        private void xrs_ValidationEventHandler(object sender, ValidationEventArgs args)
        {
            // e.Message, e.Severity (warning, error), e.Error
            // or you can access the reader if you have access to it
            // reader.LineNumber, reader.LinePosition.. etc
            return;
        }


    }
}
